package com.cws4cloud.cws.common.core.util;

import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.*;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Slf4j
public class HttpClientUtil {

    private static PoolingHttpClientConnectionManager cm;
    private static String EMPTY_STR = "";
    private static String UTF_8 = "UTF-8";

    private static void init() {
        if (cm == null) {
            cm = new PoolingHttpClientConnectionManager();
            cm.setMaxTotal(50);// 整个连接池最大连接数
            cm.setDefaultMaxPerRoute(5);// 每路由最大连接数，默认值是2
        }
    }

    /**
     * 通过连接池获取HttpClient
     *
     * @return
     */
    private static CloseableHttpClient getHttpClient() {
        init();
        return HttpClients.custom().setConnectionManager(cm).build();
    }

    /**
     * @param url
     * @return
     */
    public static HttpResult httpGetRequest(String url) {
        HttpGet httpGet = new HttpGet(url);
        return getResult(httpGet);
    }

    public static HttpResult httpGetRequest(String url, Map<String, Object> params) throws URISyntaxException {
        URIBuilder ub = new URIBuilder();
        ub.setPath(url);

        ArrayList<NameValuePair> pairs = covertParams2NVPS(params);
        ub.setParameters(pairs);

        HttpGet httpGet = new HttpGet(ub.build());
        return getResult(httpGet);
    }

    public static HttpResult httpGetRequest(String url, Map<String, Object> headers, Map<String, Object> params)
            throws URISyntaxException {
        URIBuilder ub = new URIBuilder();
        ub.setPath(url);

        ArrayList<NameValuePair> pairs = covertParams2NVPS(params);
        ub.setParameters(pairs);

        HttpGet httpGet = new HttpGet(ub.build());
        for (Map.Entry<String, Object> param : headers.entrySet()) {
            httpGet.addHeader(param.getKey(), String.valueOf(param.getValue()));
        }
        return getResult(httpGet);
    }

    public static HttpResult httpPostRequest(String url) {
        HttpPost httpPost = new HttpPost(url);
        return getResult(httpPost);
    }

    public static HttpResult httpPostRequest(String url, Map<String, Object> params) throws UnsupportedEncodingException {
        HttpPost httpPost = new HttpPost(url);
        ArrayList<NameValuePair> pairs = covertParams2NVPS(params);
        httpPost.setEntity(new UrlEncodedFormEntity(pairs, UTF_8));
        return getResult(httpPost);
    }

    public static HttpResult httpPostRequestPayLoad(String url, String strPayloadDataJson) throws UnsupportedEncodingException {
        HttpPost httpPost = new HttpPost(url);
        StringEntity stringEntity = new StringEntity(strPayloadDataJson, ContentType.APPLICATION_JSON);
        httpPost.setEntity(stringEntity);
        return getResult(httpPost);
    }

    public static HttpResult httpPostRequest(String url, Map<String, Object> headers, Map<String, Object> params)
            throws UnsupportedEncodingException {
        HttpPost httpPost = new HttpPost(url);

        for (Map.Entry<String, Object> param : headers.entrySet()) {
            httpPost.addHeader(param.getKey(), String.valueOf(param.getValue()));
        }

        ArrayList<NameValuePair> pairs = covertParams2NVPS(params);
        httpPost.setEntity(new UrlEncodedFormEntity(pairs, UTF_8));

        return getResult(httpPost);
    }

    public static HttpResult httpPostRequest(String url, List<Map> headers, Map<String, Object> params)
            throws UnsupportedEncodingException {
        HttpPost httpPost = new HttpPost(url);

        for (Map header : headers) {
            httpPost.addHeader(String.valueOf(header.get("key")), String.valueOf(header.get("value")));
        }

        ArrayList<NameValuePair> pairs = covertParams2NVPS(params);
        httpPost.setEntity(new UrlEncodedFormEntity(pairs, UTF_8));

        return getResult(httpPost);
    }

    /**
     * @Description: 发送patch请求
     * @Title: httpPatchRequestPayLoad
     * @auther: zhlj
     * @param: [url, strPayloadDataJson]
     * @date: 2020/5/26 17:48
     * @return: com.digitalchina.app.module.gateway.utils.HttpClientUtil.HttpResult
     */
    public static HttpResult httpPatchRequestPayLoad(String url, String strPayloadDataJson) throws UnsupportedEncodingException {
        HttpPatch httpPatch = new HttpPatch(url);
        StringEntity stringEntity = new StringEntity(strPayloadDataJson, ContentType.APPLICATION_JSON);
        httpPatch.setEntity(stringEntity);
        return getResult(httpPatch);
    }

    /**
     * @Description: delete请求
     * @Title: httpDeleteRequestPayLoad
     * @auther: zhlj
     * @param: [url, strPayloadDataJson]
     * @date: 2020/5/27 10:45
     * @return: com.digitalchina.app.module.gateway.utils.HttpClientUtil.HttpResult
     */
    public static HttpResult httpDeleteRequestPayLoad(String url){
        HttpDelete httpDelete = new HttpDelete(url);
        return getResult(httpDelete);
    }

    /**
     * @Description: delete请求
     * @Title: httpDeleteRequestPayLoad
     * @auther: zhlj
     * @param: [url, strPayloadDataJson]
     * @date: 2020/5/27 10:45
     * @return: com.digitalchina.app.module.gateway.utils.HttpClientUtil.HttpResult
     */
    public static HttpResult httpDeleteRequestPayLoad(String url,Map<String,Object> headers){
        HttpDelete httpDelete = new HttpDelete(url);
        for (Map.Entry<String, Object> param : headers.entrySet()) {
            httpDelete.addHeader(param.getKey(), String.valueOf(param.getValue()));
        }
        return getResult(httpDelete);
    }

    /**
     * @Description: httpOptions请求
     * @Title: httpOptionsRequest
     * @auther: zhlj
     * @param: [url, headers]
     * @date: 2020/5/27 10:45
     * @return: com.digitalchina.app.module.gateway.utils.HttpClientUtil.HttpResult
     */
    public static HttpResult httpOptionsRequest(String url,Map<String,Object> headers){
        HttpOptions httpOptions = new HttpOptions(url);
        for (Map.Entry<String, Object> param : headers.entrySet()) {
            httpOptions.addHeader(param.getKey(), String.valueOf(param.getValue()));
        }
        return getResult(httpOptions);
    }
    /**
     * @Description: httpHead请求
     * @Title: httpHeadRequest
     * @auther: zhlj
     * @param: [url, headers]
     * @date: 2020/5/27 10:45
     * @return: com.digitalchina.app.module.gateway.utils.HttpClientUtil.HttpResult
     */
    public static HttpResult httpHeadRequest(String url,Map<String,Object> headers){
        HttpHead httpHead = new HttpHead(url);
        for (Map.Entry<String, Object> param : headers.entrySet()) {
            httpHead.addHeader(param.getKey(), String.valueOf(param.getValue()));
        }
        return getResult(httpHead);
    }

    /**
     * @Description: put请求
     * @Title: httpPutRequest
     * @auther: zhlj
     * @param: [url, headers]
     * @date: 2020/5/27 10:45
     * @return: com.digitalchina.app.module.gateway.utils.HttpClientUtil.HttpResult
     */
    public static HttpResult httpPutRequest(String url,Map<String,Object> headers){
        HttpPut httpPut = new HttpPut(url);
        for (Map.Entry<String, Object> param : headers.entrySet()) {
            httpPut.addHeader(param.getKey(), String.valueOf(param.getValue()));
        }
        return getResult(httpPut);
    }

    public static HttpResult httpAllRequest(String requestMethod, String requestUrl,Map<String,Object> headerMap,Map<String,Object> paramsMap){
        HttpResult httpResult = null;
        try {
        if (HttpPost.METHOD_NAME.equals(requestMethod)){
                httpResult = HttpClientUtil.httpPostRequest(requestUrl,headerMap,paramsMap);
        } else if (HttpGet.METHOD_NAME.equals(requestMethod)){
            httpResult = HttpClientUtil.httpGetRequest(requestUrl,headerMap,paramsMap);
        } else if (HttpDelete.METHOD_NAME.equals(requestMethod)){
            httpResult = HttpClientUtil.httpDeleteRequestPayLoad(markGetUrl(requestUrl,paramsMap),headerMap);
        } else if (HttpPut.METHOD_NAME.equals(requestMethod)){
            httpResult = HttpClientUtil.httpPutRequest(markGetUrl(requestUrl,paramsMap),headerMap);
        } else if (HttpPatch.METHOD_NAME.equals(requestMethod)){
            httpResult = HttpClientUtil.httpPatchRequestPayLoad(requestUrl, JSONUtil.toJsonStr(paramsMap));
        } else if (HttpOptions.METHOD_NAME.equals(requestMethod)){
            httpResult = HttpClientUtil.httpOptionsRequest(markGetUrl(requestUrl,paramsMap),headerMap);
        } else if (HttpHead.METHOD_NAME.equals(requestMethod)){
            httpResult = HttpClientUtil.httpHeadRequest(markGetUrl(requestUrl,paramsMap),headerMap);
        }
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (URISyntaxException e) {
            e.printStackTrace();
        }
        return httpResult;
    }

    private static String markGetUrl(String url, Map<String, Object> queryParamMap){
        String finalUrl = url;
        if (queryParamMap!=null && queryParamMap.size()>0) {
            finalUrl = url + "?";
            for(Map.Entry<String,Object> entry : queryParamMap.entrySet()){
                finalUrl += entry.getKey() + "=" + entry.getValue() + "&";
            }
            finalUrl = finalUrl.substring(0, finalUrl.length()-1);	// 后缀处理，去除 ？ 或 & 符号
        }
        return finalUrl;
    }

    private static ArrayList<NameValuePair> covertParams2NVPS(Map<String, Object> params) {
        ArrayList<NameValuePair> pairs = new ArrayList<NameValuePair>();
        for (Map.Entry<String, Object> param : params.entrySet()) {
            pairs.add(new BasicNameValuePair(param.getKey(), String.valueOf(param.getValue())));
        }

        return pairs;
    }


    /**
     * 处理Http请求
     *
     * @param request
     * @return
     */
    private static HttpResult getResult(HttpRequestBase request) {

        CloseableHttpClient httpClient = getHttpClient();
        CloseableHttpResponse response = null;
        int code = 0;
        String result = "";
        try {
            response = httpClient.execute(request);
            code = response.getStatusLine().getStatusCode();
            if (response.getEntity() != null) {
                result = EntityUtils.toString(response.getEntity());
            }
        } catch (ClientProtocolException e) {
            result=e.getMessage();
            code = HttpStatus.SC_PAYMENT_REQUIRED;
            log.error("获取结果错误", e);
        } catch (IOException e) {
            result=e.getMessage();
            code = HttpStatus.SC_PAYMENT_REQUIRED;
            log.error("获取结果错误", e);
        } finally {
            try {
                if (response != null) {
                    response.close();
                }
            } catch (IOException e) {
                log.error("关闭response错误", e);
            }
        }
        return new HttpResult(code, result);
    }

    public static class HttpResult {
        private Integer code;
        private String result;

        private HttpResult() {

        }

        public HttpResult(int code, String result) {
            this.code = code;
            this.result = result;
        }

        public Integer getCode() {
            return code;
        }

        public void setCode(Integer code) {
            this.code = code;
        }

        public String getResult() {
            return result;
        }

        public void setResult(String result) {
            this.result = result;
        }
    }

}
